home *** CD-ROM | disk | FTP | other *** search
/ Columbia Kermit / kermit.zip / newsgroups / misc.20030409-20031118 / 000185_kleine@fh-jena.de_Sun Jun 22 12:57:57 EDT 2003.msg < prev    next >
Text File  |  2020-01-01  |  58KB  |  2,483 lines

  1. Article: 14414 of comp.protocols.kermit.misc
  2. Path: newsmaster.cc.columbia.edu!phl-feed.news.verio.net!nntp1.tagonline.com!nycmny1-snf1.gtei.net!nycmny1-snh1.gtei.net!news.gtei.net!newsfeed!fu-berlin.de!news.uni-leipzig.de!news.uni-jena.de!news.fh-jena.de!not-for-mail
  3. From: Prof Karl Kleine <kleine@fh-jena.de>
  4. Newsgroups: comp.protocols.kermit.misc
  5. Subject: Re: cutape
  6. Date: Sun, 22 Jun 2003 11:32:58 +0000 (UTC)
  7. Organization: Fachhochschule Jena, Germany
  8. Lines: 2461
  9. Sender: Prof Karl Kleine <kleine@hoare.gw.fh-jena.de>
  10. Message-ID: <bd445a$tbh$2@beta.szi.fh-jena.de>
  11. References: <3834495c.0306031601.34eb05ba@posting.google.com> <bbl8ah$pvn$1@watsol.cc.columbia.edu> <3834495c.0306041602.353fa8d6@posting.google.com> <bbnien$ebu$1@watsol.cc.columbia.edu> <3834495c.0306051454.29aa1356@posting.google.com> <bd41r3$tbh$1@beta.szi.fh-jena.de>
  12. NNTP-Posting-Host: hoare.gw.fh-jena.de
  13. Mime-Version: 1.0
  14. Content-Type: text/plain; charset=ISO-8859-1
  15. Content-Transfer-Encoding: 8bit
  16. X-Trace: beta.szi.fh-jena.de 1056281578 30065 194.94.38.12 (22 Jun 2003 11:32:58 GMT)
  17. X-Complaints-To: news@beta.szi.fh-jena.de
  18. NNTP-Posting-Date: Sun, 22 Jun 2003 11:32:58 +0000 (UTC)
  19. User-Agent: tin/1.4.2-20000205 ("Possession") (UNIX) (Linux/2.2.16 (i686))
  20. Xref: newsmaster.cc.columbia.edu comp.protocols.kermit.misc:14414
  21.  
  22. Prof Karl Kleine <kleine@fh-jena.de> wrote:
  23.  
  24. >     google in usenet groups for my old posting of
  25. >     "sltape", which does exactly what you need. It
  26. >     reads and writes both ANSI and IBM/MVS tapes
  27. >     on Unix systems. Written in C (K&R).
  28.  
  29. > kl
  30.  
  31.     oops... sltape was the name of the original version.
  32.     better look for slt.c, resp. slt-20.c (the version 2)
  33.     that I made available. google/usenet has a shar-archive.
  34.  
  35.     but to make it even easier for you, I digged it from my
  36.     own archives, and include it at the end of this message.
  37.  
  38. ________________________________________________________
  39. Prof. Karl Kleine          http://www.fh-jena.de/~kleine
  40. Fachhochschule Jena        kleine@fh-jena.de
  41. Carl-Zeiss-Promenade 2     +49-3641-205-502 [fax -503]
  42. D-07745 Jena, Germany
  43.  
  44.  
  45. =============================================================================
  46.  
  47. #!/bin/sh
  48. # This is a shell archive (produced by shar 3.49)
  49. # To extract the files from this archive, save it to a file, remove
  50. # everything above the "!/bin/sh" line above, and type "sh file_name".
  51. #
  52. # made 06/30/1994 19:27 UTC by kleine@bullerbue
  53. # Source directory /usr/fhj/gw/kleine/binsrc
  54. #
  55. # existing files will NOT be overwritten unless -c is specified
  56. #
  57. # This shar contains:
  58. # length  mode       name
  59. # ------ ---------- ------------------------------------------
  60. #   6986 -rw-r----- slt-20.1
  61. #  43183 -rw-r----- slt-20.c
  62. #
  63. # ============= slt-20.1 ==============
  64. if test -f 'slt-20.1' -a X"$1" != X"-c"; then
  65.     echo 'x - skipping slt-20.1 (File already exists)'
  66. else
  67. echo 'x - extracting slt-20.1 (Text)'
  68. sed 's/^X//' << 'SHAR_EOF' > 'slt-20.1' &&
  69. .\" pltroff -manl $1
  70. .tr ~"
  71. .if t .ds i \(fm\(fm
  72. .if n .ds i ""
  73. .TH SLT 1 FZI-Karlsruhe
  74. .SH NAME
  75. slt \- standard labelled tape processing
  76. .SH SYNOPSIS
  77. .B slt
  78. [
  79. .B -i
  80. ]
  81. [
  82. .B -t
  83. tapefile
  84. ]
  85. .B -l
  86. .PP
  87. .B slt
  88. [
  89. .B -i
  90. ]
  91. [
  92. .B -t
  93. tapefile
  94. ]
  95. [
  96. .B -s
  97. ]
  98. .B -x
  99. [
  100. file ...
  101. ]
  102. .PP
  103. .B slt
  104. [
  105. .B -i
  106. ]
  107. [
  108. .B -t
  109. tapefile
  110. ]
  111. [
  112. .B -s
  113. ]
  114. .B -c
  115. volser owner file/format ...
  116. .SH DESCRIPTION
  117. .I Slt
  118. creates, reads, and lists industry standard \(12" magnetic tapes
  119. according to the
  120. .B "ANSI\|X3.27-1987"
  121. standard entitled
  122. .BR "Magnetic tape labels and file structure for information interchange" .
  123. Internationally, this standard was also adopted by ISO as
  124. .B "ISO\|1001"
  125. and in Germany by DIN as
  126. .BR "DIN\|66029" .
  127. Slt also reads and writes tapes according other editions of these standards.
  128. .PP
  129. If
  130. .I slt
  131. is invoked with a first argument
  132. .BR -i ,
  133. the tape format is IBM/OS standard labelled,
  134. which is similar to the ANSI format, and documented in the IBM manual
  135. .BR "OS\|/\|VS Tape Labels" ,
  136. GC26-3795.
  137. IBM tapes are in the EBCDIC character set.
  138. .PP
  139. .I Slt
  140. is intended for interchange of textual information between
  141. a very wide variety of machines and operating systems,
  142. structured as sequence of lines, generally called records.
  143. In the Unix world a record is a sequence of characters
  144. separated by newline characters.
  145. The characteristics of magnetic tape drives require to put several
  146. records into a larger unit called a block which can be stored on tape.
  147. The relation between blocks and records is called a format, which may be
  148. fixed, where all record have the same length, or variable, where additional
  149. information is stored to describe the length of each record.
  150. .PP
  151. When writing a file onto tape in fixed format, each record is padded
  152. with blanks to the record length, resp. truncated to that length.
  153. Truncations are reported.
  154. Reading a fixed format file reverses that process by removing all trailing
  155. blanks from a line.
  156. .PP
  157. There are three tape processing options:
  158. .TP
  159. .B "-l"
  160. List contents of tape: Label, owner, and then for each file on the tape,
  161. its position, its name, number of blocks, record format,
  162. block and record sizes, creation and expiration dates
  163. is written to standard output.
  164. .TP
  165. .B "-x"
  166. Extract files from tape:
  167. If specified without further parameters, all files are extracted from the tape.
  168. Names are taken from the file header label and translated to lowercase letters.
  169. For non-BSD Unix systems, truncation to 14 characters takes place.
  170. .TP
  171. .BI "-x" "\ \ filename ..."
  172. Extract specific files from tape:
  173. The first file is give the first name provided, the second file the second
  174. name, until the list of names is exhausted.
  175. Files on tape can be skipped by specifying
  176. .I "/dev/null"
  177. or some other junk name as output filename.
  178. .TP
  179. .BI "-c" "\ \ volser\ \ owner\ \ filename/format ..."
  180. Create new tape:
  181. Write a volume label with the volume serial number
  182. .I volser
  183. (max. 6 characters)
  184. and owner name
  185. .I owner
  186. (max. 10 characters).
  187. .I Volser
  188. is also known as "the tape label".
  189. Then append files or change format for files following.
  190. Format and file secifications may freely be mixed.
  191. Unix filenames are stripped of all directory prefixes and are
  192. translated to uppercase.
  193. Wildcarding is supported by shell expansion of filenames prior to execution of
  194. .IR slt .
  195. .PP
  196. Format specifications for newly created tapes:
  197. .TP
  198. .B -ff
  199. Fixed (blocked) format. See above for padding and truncation.
  200. .TP
  201. .B -fd
  202. Variable record format (ANSI).
  203. The record length specifies the maximum size of a line of text.
  204. .TP
  205. .B -fv
  206. Variable record format (IBM).
  207. The
  208. .B -fv
  209. and
  210. .B -fd
  211. formats are synonyms.
  212. .TP
  213. .B -fu
  214. The record format is undefined.
  215. There is no interpretation of the data written to tape; it is just a
  216. byte stream written to tape in blocks of the size specified.
  217. .TP
  218. .BI -b n
  219. The block length is set to
  220. .IR n ,
  221. which must be in the range 18 to 2048 for ANSI tapes.
  222. IBM tapes can have a larger block size.
  223. .TP
  224. .BI -r n
  225. The record length is set to
  226. .IR n .
  227. For fixed (blocked) format, the blocksize must be a multiple
  228. of the record length.
  229. .PP
  230. New settings are reported when the next file is written.
  231. Default format is ANSI standard, blocksize 2048, recordlength 512,
  232. variable record format.
  233. For IBM tapes, the default is blocksize 1600, recordlength 80,
  234. fixed record format.
  235. .PP
  236. An alternate tape drive can be specified by the
  237. .B -t
  238. .I tapefile
  239. option, where
  240. .I tapefile
  241. must be a raw device (character special file) specification for a tape drive,
  242. like
  243. .IR /dev/rmt2 .
  244. .PP
  245. By default,
  246. .I slt
  247. writes a VOL1 header according to the 4th edition (ANSI X3.27-1987) of the
  248. standard. You can also select previous editions by suffixing the
  249. .B -c
  250. option with the edition number, e.g.
  251. .BI -c 3.
  252. .PP
  253. Usually
  254. .I slt
  255. reports what it is doing by messages written to standard output.
  256. You can redirect or
  257. .I tee
  258. this output to a file to get a log what's on the tape,
  259. and send this log with the tape to other sites.
  260. Logging can be suppressed by the silence option
  261. .BR -s .
  262. .PP
  263. Invoking
  264. .I slt
  265. with the help option
  266. .B -h
  267. will print a brief summary of commands.
  268. .PP
  269. When a tape is given to you with the notice that is follows the standard, but
  270. .I slt
  271. does not agree,
  272. the debugging option
  273. .B -D
  274. in front of
  275. .B -l
  276. will log the tape labels.
  277. For interpretation, you should be familiar with the standard definitions.
  278. (If unsuccessful or in doubt, you might also try the
  279. .I analtape
  280. utility by the same author).
  281. .PP
  282. All option flags may also be specified in uppercase.
  283. .SH EXAMPLES
  284. .TP 15
  285. .I "slt\ \ -i\ \ -l"
  286. List all files on an IBM tape.
  287. .TP 15
  288. .I "slt\ \ -x\ \ x\ \ x\ \ x\ \ x\ \ f5\ \ f6"
  289. Skip four files by reading them all into a scratch file
  290. .I x
  291. and then read the 5th and 6th file as files
  292. .I f5
  293. and
  294. .IR f6 .
  295. .TP 15
  296. .I "slt\ \ -c\ \ mytape\ \ whizzard"
  297. Initialize the tape with only a volume label
  298. .I MYTAPE
  299. for owner
  300. .IR WHIZZARD .
  301. Note that these values are always written in uppercase in tape labels.
  302. .TP 15
  303. .I "slt\ \ -c\ \ slt\ \ kleine\ \ slt.c\ \ slt.1"
  304. Create an ANSI tape, labelled
  305. .I SLT
  306. for owner
  307. .I KLEINE
  308. containing two files
  309. .I SLT.C
  310. (the sourcetext of the slt program)
  311. and
  312. .I SLT.1
  313. (the nroff/troff input text for the manual page you are just reading)
  314. in the standard format.
  315. .TP 15
  316. .I "slt\ \ -i\ \ -c\ \ xyz789\ \ poorguy\ \ -ff\ \ -b4000\ \ -r80\ \ punched\ \ cards"
  317. Create an IBM/OS tape for
  318. .I POORGUY
  319. labelled
  320. .I XYZ789
  321. with two files
  322. .I PUNCHED
  323. and
  324. .I CARDS
  325. in 80/4000 fixed blocked format.
  326. .SH FILES
  327. /dev/rmt0
  328. .SH AUTHOR
  329. Karl Kleine, Forschungszentrum Informatik, Karlsruhe, Germany,
  330. (kleine@fzi.de), 1985 to 1992, based on an earlier program
  331. .I sltape
  332. by H. M. Stahl, KUN Nijmegen (NL)
  333. .SH SHORTCOMINGS
  334. .I Slt
  335. does not support multi-volume files, volume sets, spanned records.
  336. Furthermore, only complete tapes can be written;
  337. there is no support for adding files to an existing sequence of files
  338. on a tape.
  339. .I Slt
  340. is intended for interchange of textual information,
  341. and has not been tested on binary information.
  342. The character code translation for ibm tapes may differ from what
  343. siemens or ibm expect.
  344. X
  345. SHAR_EOF
  346. chmod 0640 slt-20.1 ||
  347. echo 'restore of slt-20.1 failed'
  348. Wc_c="`wc -c < 'slt-20.1'`"
  349. test 6986 -eq "$Wc_c" ||
  350.     echo 'slt-20.1: original size 6986, current size' "$Wc_c"
  351. fi
  352. # ============= slt-20.c ==============
  353. if test -f 'slt-20.c' -a X"$1" != X"-c"; then
  354.     echo 'x - skipping slt-20.c (File already exists)'
  355. else
  356. echo 'x - extracting slt-20.c (Text)'
  357. sed 's/^X//' << 'SHAR_EOF' > 'slt-20.c' &&
  358. #
  359. /*************************************************************************
  360. **************************************************************************
  361. ***
  362. ***    s l t         standard labelled tape
  363. ***
  364. ***    according to    - ANSI X3.27-1978  (DIN 66029)
  365. ***            - IBM OS/VS Tape Labels (IBM Doc GC-26-3795-3)
  366. ***
  367. ***    written by    Karl Kleine, FZI Karlsruhe
  368. ***    adapted from    'sltape' by H.M.Stahl,
  369. ***            Kath. University of Nijmegen (NL), Informatika
  370. ***
  371. ***    version        march 1992, see program history and PROGID below
  372. ***
  373. ***    usage
  374. ***        listing contents of tape
  375. ***
  376. ***            slt [ -i ] -l
  377. ***
  378. ***        creating a new tape (writing disk to tape)
  379. ***
  380. ***            slt [ -i ] -c volser owner ffs
  381. ***
  382. ***            where    volser    is volume serial number (6 chars)
  383. ***
  384. ***                owner    is owner (10 chars)
  385. ***
  386. ***                ffs    is a format / file name sequence
  387. ***
  388. ***                format    consists of three specs:
  389. ***                    record format (-f), block (-b),
  390. ***                    and record length (-r) as follows:
  391. ***
  392. ***                    -ff    fixed (blocked) format
  393. ***                    -fv    variable format (ibm)
  394. ***                    -fd    variable format (ansi)
  395. ***                    -fu    undefined
  396. ***                    -bn    specifies blocklength,
  397. ***                        where n is 18 .. 2048
  398. ***                    -rn    specifies record length,
  399. ***                        where n is a suitable number
  400. ***
  401. ***                    default format is ansi d format with
  402. ***                    blocksize 2048, recordlength 512.
  403. ***
  404. ***                file name sequence is a sequence of unix
  405. ***                names. if pathnames are specified, directory
  406. ***                prefixes are stripped.
  407. ***
  408. ***            example:  slt -i -c slt kleine -ff -b2000 -r80 slt.c
  409. ***                this creates a new tape holding one file
  410. ***                in ibm/os format, fixed blocked 2000/80.
  411. ***
  412. ***            the -c option can be followed by a digit 1 to 4,
  413. ***            defining the standard version. in essence we follow
  414. ***            the common rules, als already defined in version 1
  415. ***            of the standard. default is version / level 4 (1987).
  416. ***            4:    ANSI X3.27-1987        DIN 66029 Aug 1987
  417. ***            3:    ANSI X3.27-1978        DIN 66029 Mai 1979
  418. ***            2:                DIN 66029 Jun 1976
  419. ***            1:    ANSI X3.27-1969        DIN 66029 Aug 1972
  420. ***
  421. ***        extracting files from tape
  422. ***
  423. ***            slt [ -i ] -x file1 file2 ...
  424. ***
  425. ***                extracts as many files as given from tape
  426. ***                and assigns the names specified to them.
  427. ***
  428. ***            slt [ -i ] -x
  429. ***
  430. ***                if no names are specified, all files are
  431. ***                extracted. attention: the file names on tape
  432. ***                are 17 characters long, whereas unix (std)
  433. ***                names are are only 14 chars long. this may
  434. ***                result in duplicate names and overwriting
  435. ***                of files previously extracted. in this case
  436. ***                you have to resort to explicit extraction.
  437. ***
  438. ***        spefication of an alternate tape drive
  439. ***
  440. ***            slt [ -i ] -t tapedrive ....
  441. ***
  442. ***        tapedrive must be a raw device which specifies a tape drive,
  443. ***        e.g. /dev/rmt2, /dev/rmt0h, whatever it's called in your UNIX
  444. ***
  445. ***        the -s option switches to silent mode. by default, slt will
  446. ***        log on standard output what is is doing in some detail.
  447. ***
  448. ***        the option -i specifies IBM/OS tape standard to be used in
  449. ***        contrast to the default ANSI tape standard. if specified,
  450. ***        this option must be given first.
  451. ***
  452. ***        the debug option -D reports details of tape labels
  453. ***        in case of doubt. useful when slt refuses to read a tape
  454. ***        which was said to adhere to one of the standards.
  455. ***
  456. ***        all options are also accepted in upper case.
  457. ***
  458. ***        volser, owner, and file names are all translated to
  459. ***        upper case when writing them to tape. similarly,
  460. ***        file names are converted to lower case on extraction.
  461. ***
  462. **************************************************************************
  463. *************************************************************************/
  464. X
  465. X
  466. /* revision history:
  467. **    V1.0    08-FEB-1985    Karl Kleine, FZI KA
  468. **                prototype finished, put into use on
  469. **                PCS - F2 of GMDKA at FZI.
  470. **    V1.1    31-MAY-1985    blocksize enlarged for ibm tapes,
  471. **                minor cleanups
  472. **                unix manual page (slt.1) written
  473. **    V1.2    10-MAR-1987    sun version / just the program id
  474. **    V1.3    28-APR-1989    enlarged temp buf, silly, but shortcut.
  475. **    V1.4    26-APR-1990    SunOS 4 version
  476. **
  477. **    V2.0    23-MAR-1992    cleanup, removal of old PCS hacks,
  478. **                tape selection and proper tape ioctl handling
  479. */
  480. X
  481. #define    PROGID    "V2.0 of 23-MAR-1992"
  482. X
  483. /* one of the symbols BSD42, SUNOS3, SUNOS4, ULTRIX4 must be defined.
  484. /* add more machines as needed
  485. */
  486. X
  487. #define K    1024
  488. X
  489. #ifdef    BSD42
  490. #define    SYSID    "SLT20-BSD42"
  491. #define    TAPE    "/dev/nrmt0"
  492. #define UBLKS    1024
  493. #define    TMPSIZ    32*K
  494. #define    SETUP    1
  495. #endif
  496. X
  497. #ifdef    SUNOS3
  498. #define    SYSID    "SLT20-SUNOS3"
  499. #define    TAPE    "/dev/nrmt0"
  500. #define    UBLKS    1024
  501. #define    TMPSIZ    32*K
  502. #define    SETUP    1
  503. #endif
  504. X
  505. #ifdef    SUNOS4
  506. #define    SYSID    "SLT20-SUNOS4"
  507. #define    TAPE    "/dev/nrmt0"
  508. #define    UBLKS    4*K
  509. #define    TMPSIZ    32*K
  510. #include <sys/types.h>
  511. #define    SETUP    1
  512. #endif
  513. X
  514. #ifdef    ULTRIX4
  515. #define    SYSID    "SLT20-ULTRIX4"
  516. #define    TAPE    "/dev/nrmt0h"
  517. #define    UBLKS    4*K
  518. #define    TMPSIZ    32*K
  519. #define    SETUP    1
  520. #endif
  521. X
  522. /* a generic definition, check if this fits you, or make another entry */
  523. X
  524. #ifndef SETUP
  525. #define    SYSID    "SLT20-UNIX"
  526. #define TAPE    "/dev/nrmt0"
  527. #define    UBLKS    1024
  528. #define    TMPSIZ    32*K
  529. #define    SETUP    1
  530. #endif
  531. X
  532. X
  533. /*************************************************************************
  534. ***    label field definitions
  535. *************************************************************************/
  536. X
  537. X                /* constants for all tape labels */
  538. #define    LABLEN    80
  539. #define MAXLABLEN    512
  540. #define    LIDPOS    0
  541. #define    LIDLEN    4
  542. X                /* constants for VOL label */
  543. #define    SERPOS    4
  544. #define SERLEN    6
  545. #define VR1POS    10
  546. #define    OWNPOS    41
  547. #define OWNLEN    10
  548. #define LSLPOS    79
  549. #define LSLLEN    1
  550. X                /* constants for HDR / EOF 1 label */
  551. #define    DSNPOS    4
  552. #define    DSNLEN    17
  553. #define    DSSRPOS    21
  554. #define DSSRLEN    6
  555. #define    VSSNPOS    27
  556. #define    VSSNLEN    4
  557. #define    DSSNPOS    31
  558. #define DSSNLEN    4
  559. #define    GENNPOS    35
  560. #define GENNLEN    4
  561. #define    GVNPOS    39
  562. #define GVNLEN    2
  563. #define    CDPOS    41
  564. #define CDLEN    6
  565. #define    EDPOS    47
  566. #define EDLEN    6
  567. #define    DSSPOS    53
  568. #define    BCPOS    54
  569. #define BCLEN    6
  570. #define    SCPOS    60
  571. #define SCLEN    13
  572. X                /* constants for HDR / EOF 2 label */
  573. #define    RFPOS    4
  574. #define RFLEN    1
  575. #define    BLPOS    5
  576. #define    BLLEN    5
  577. #define    RLPOS    10
  578. #define    RLLEN    5
  579. #define    TDPOS    15
  580. #define    DSPPOS    16
  581. #define    JIPOS    17
  582. #define    JILEN    17
  583. #define    TRTPOS    34
  584. #define    TRTLEN    2
  585. #define    PCCPOS    36
  586. #define    R1POS    37
  587. #define    BAPOS    38
  588. #define    R2POS    39
  589. #define    R2LEN    41
  590. #define BOPOS    50
  591. X
  592. X
  593. /*************************************************************************
  594. ***    character translation tables  ASCII <--> EBCDIC
  595. *************************************************************************/
  596. X
  597. char    etoa[] =                /* EBCDIC to ASCII */
  598. {
  599. X    0000,0001,0002,0003,0234,0011,0206,0177,
  600. X    0227,0215,0216,0013,0014,0015,0016,0017,
  601. X    0020,0021,0022,0023,0235,0205,0010,0207,
  602. X    0030,0031,0222,0217,0034,0035,0036,0037,
  603. X    0200,0201,0202,0203,0204,0012,0027,0033,
  604. X    0210,0211,0212,0213,0214,0005,0006,0007,
  605. X    0220,0221,0026,0223,0224,0225,0226,0004,
  606. X    0230,0231,0232,0233,0024,0025,0236,0032,
  607. X    0040,0240,0241,0242,0243,0244,0245,0246,
  608. X    0247,0250,0133,0056,0074,0050,0053,0041,
  609. X    0046,0251,0252,0253,0254,0255,0256,0257,
  610. X    0260,0261,0135,0044,0052,0051,0073,0136,
  611. X    0055,0057,0262,0263,0264,0265,0266,0267,
  612. X    0270,0271,0174,0054,0045,0137,0076,0077,
  613. X    0272,0273,0274,0275,0276,0277,0300,0301,
  614. X    0302,0140,0072,0043,0100,0047,0075,0042,
  615. X    0303,0141,0142,0143,0144,0145,0146,0147,
  616. X    0150,0151,0304,0305,0306,0307,0310,0311,
  617. X    0312,0152,0153,0154,0155,0156,0157,0160,
  618. X    0161,0162,0313,0314,0315,0316,0317,0320,
  619. X    0321,0176,0163,0164,0165,0166,0167,0170,
  620. X    0171,0172,0322,0323,0324,0325,0326,0327,
  621. X    0330,0331,0332,0333,0334,0335,0336,0337,
  622. X    0340,0341,0342,0343,0344,0345,0346,0347,
  623. X    0173,0101,0102,0103,0104,0105,0106,0107,
  624. X    0110,0111,0350,0351,0352,0353,0354,0355,
  625. X    0175,0112,0113,0114,0115,0116,0117,0120,
  626. X    0121,0122,0356,0357,0360,0361,0362,0363,
  627. X    0134,0237,0123,0124,0125,0126,0127,0130,
  628. X    0131,0132,0364,0365,0366,0367,0370,0371,
  629. X    0060,0061,0062,0063,0064,0065,0066,0067,
  630. X    0070,0071,0372,0373,0374,0375,0376,0377,
  631. };
  632. X
  633. char    atoe[] =                /* ASCII to EBCDIC */
  634. {
  635. X    0000,0001,0002,0003,0067,0055,0056,0057,
  636. X    0026,0005,0045,0013,0014,0015,0016,0017,
  637. X    0020,0021,0022,0023,0074,0075,0062,0046,
  638. X    0030,0031,0077,0047,0034,0035,0036,0037,
  639. X    0100,0117,0177,0173,0133,0154,0120,0175,
  640. X    0115,0135,0134,0116,0153,0140,0113,0141,
  641. X    0360,0361,0362,0363,0364,0365,0366,0367,
  642. X    0370,0371,0172,0136,0114,0176,0156,0157,
  643. X    0174,0301,0302,0303,0304,0305,0306,0307,
  644. X    0310,0311,0321,0322,0323,0324,0325,0326,
  645. X    0327,0330,0331,0342,0343,0344,0345,0346,
  646. X    0347,0350,0351,0112,0340,0132,0137,0155,
  647. X    0171,0201,0202,0203,0204,0205,0206,0207,
  648. X    0210,0211,0221,0222,0223,0224,0225,0226,
  649. X    0227,0230,0231,0242,0243,0244,0245,0246,
  650. X    0247,0250,0251,0300,0152,0320,0241,0007,
  651. X    0040,0041,0042,0043,0044,0025,0006,0027,
  652. X    0050,0051,0052,0053,0054,0011,0012,0033,
  653. X    0060,0061,0032,0063,0064,0065,0066,0010,
  654. X    0070,0071,0072,0073,0004,0024,0076,0341,
  655. X    0101,0102,0103,0104,0105,0106,0107,0110,
  656. X    0111,0121,0122,0123,0124,0125,0126,0127,
  657. X    0130,0131,0142,0143,0144,0145,0146,0147,
  658. X    0150,0151,0160,0161,0162,0163,0164,0165,
  659. X    0166,0167,0170,0200,0212,0213,0214,0215,
  660. X    0216,0217,0220,0232,0233,0234,0235,0236,
  661. X    0237,0240,0252,0253,0254,0255,0256,0257,
  662. X    0260,0261,0262,0263,0264,0265,0266,0267,
  663. X    0270,0271,0272,0273,0274,0275,0276,0277,
  664. X    0312,0313,0314,0315,0316,0317,0332,0333,
  665. X    0334,0335,0336,0337,0352,0353,0354,0355,
  666. X    0356,0357,0372,0373,0374,0375,0376,0377,
  667. };
  668. X
  669. X
  670. /*************************************************************************
  671. ***    unix system includes needed
  672. *************************************************************************/
  673. X
  674. #include <time.h>
  675. #include <stdio.h>
  676. #include <fcntl.h>
  677. #include <errno.h>
  678. #include <sys/ioccom.h>
  679. #include <sys/mtio.h>
  680. X
  681. X
  682. /*************************************************************************
  683. ***    global variables
  684. *************************************************************************/
  685. X
  686. int operation;                /* kind of operation wanted    */
  687. #define NOOPER        0
  688. #define    CREATAPE    1
  689. #define    READTAPE    2
  690. #define    LISTTAPE    3
  691. X
  692. int standard;                /* which standard ?        */
  693. #define    ANSISTD    0
  694. #define    IBMSTD    1
  695. char *stdlevel;                /* ANSI std level; default "4"    */
  696. X
  697. char *tapename;                /* name of tape device         */
  698. int tapefid;                /* unix file identifier for it    */
  699. X
  700. char *volser;                /* volume serial number        */
  701. char *owner;                /* tape owner name        */
  702. int fseqno;                /* file sequence number on tape    */
  703. int recfm;                /* record format        */
  704. #define    FIXED    'f'
  705. #define    VAR    'v'
  706. #define AVAR    'd'
  707. #define UNDEF    'u'
  708. int blksize;                /* blocksize            */
  709. int lrecl;                /* record length        */
  710. int fchange;                /* any of recfm, blksize, lrecl    */
  711. X                    /* changed? needs reporting    */
  712. int truncated;                /* no of truncated records      */
  713. X
  714. X                    /* extra space at end of buffer    */
  715. X                    /* for NULL chars (printf %s)    */
  716. char vollab[LABLEN+2];            /* volume label buffer        */
  717. char hdr1lab[LABLEN+2];            /* HDR1 / EOF1 buffer        */
  718. char hdr2lab[LABLEN+2];            /* HDR2 / EOF2 buffer        */
  719. X
  720. char temp[TMPSIZ];            /* temporary string buffer    */
  721. X                    /* indecently large, should be    */
  722. X                    /* allocated dynamically, but..    */
  723. X
  724. int diskfid;                /* unix file identifier for     */
  725. X                    /* disk file to read / write    */
  726. X
  727. long clock;                /* see time(2), resp. ctime(3)    */
  728. int verbose;                /* report details flag        */
  729. int debug;                /* there is always a bug...    */
  730. X
  731. X
  732. /*************************************************************************
  733. ***    main program
  734. *************************************************************************/
  735. X
  736. main (argc, argv)
  737. X    int argc;
  738. X    char *argv[];
  739. {
  740. X    register int i;
  741. X    register int c;
  742. X    char *ctime();
  743. X    char std;
  744. X
  745. X    /* check for legal configuration data first */
  746. X    if (sizeof(SYSID) > 13) {
  747. X        printf (stderr, "Systemid %s not ANSI X3.27 conformant (>13)\n",
  748. X            SYSID);
  749. X        exit (-1);
  750. X    }
  751. X
  752. X    /* identify yourself and tell the time (for a possible log) */
  753. X    time (&clock);
  754. X    printf ("slt %s / %s run at %s\n", PROGID, SYSID, ctime (&clock));
  755. X
  756. X    /* set defaults */
  757. X    tapename = TAPE;
  758. X    operation = NOOPER;        /* none specified yet */
  759. X    standard = ANSISTD;        /* assume ANSI standard */
  760. X    stdlevel = "4";
  761. X    fchange = 1;            /* set format */
  762. X    recfm = AVAR;
  763. X    blksize = 2048;
  764. X    lrecl = 512;
  765. X    verbose = 1;            /* report by default */
  766. X    fseqno = 0;            /* no file touched yet */
  767. X    debug = 0;
  768. X
  769. X    /* go thru argument list */
  770. X    for (i = 1; i < argc; i++)
  771. X    {
  772. X        if ( (c=argv[i][0]) == '-')
  773. X        {
  774. X            switch( argv[i][1])
  775. X            {
  776. X            case 'i':    /* -i for IBM tape std */
  777. X            case 'I':    /* if specified, flag must be first */
  778. X                if (i != 1)
  779. X                    stopit ("-i flag must be first");
  780. X                /* set IBM std and associated dflt format */
  781. X                standard = IBMSTD;
  782. X                recfm = FIXED;    /* good old card images */
  783. X                blksize = 1600; /* ibm seems to like it */
  784. X                lrecl = 80;
  785. X                break;
  786. X
  787. X            case 'b':    /* define blocksize */
  788. X            case 'B':
  789. X                blksize = atoi (&argv[i][2]);
  790. X                fchange++;
  791. X                break;
  792. X
  793. X            case 'r':    /* define record length */
  794. X            case 'R':
  795. X                lrecl = atoi (&argv[i][2]);
  796. X                fchange++;
  797. X                break;
  798. X
  799. X            case 'f':    /* define record format */
  800. X            case 'F':
  801. X                c = argv[i][2];
  802. X                switch (c)
  803. X                {
  804. X                    case 'f':
  805. X                    case 'F':
  806. X                        recfm = FIXED;
  807. X                        break;
  808. X                    case 'v':
  809. X                    case 'V':
  810. X                    case 'd':
  811. X                    case 'D':
  812. X                        if (standard == ANSISTD)
  813. X                            recfm = AVAR;
  814. X                        else
  815. X                            recfm = VAR;
  816. X                        break;
  817. X                    case 'u':
  818. X                    case 'U':
  819. X                        recfm = UNDEF;
  820. X                        lrecl = blksize;
  821. X                        break;
  822. X                    case 's':
  823. X                    case 'S':
  824. X                        err ("Spanned records not supported");
  825. X                        break;
  826. X                    default:
  827. X                        err ("Bad format spec");
  828. X                }
  829. X                fchange++;
  830. X                break;
  831. X
  832. X            case 'c':    /* create a new tape */
  833. X            case 'C':
  834. X                std = (char)argv[i][2];
  835. X                if ('1'<=std && std<='4')
  836. X                    stdlevel[0] = std;
  837. X                if (operation != NOOPER)
  838. X                    stopit ("Can't redefine operation");
  839. X                operation = CREATAPE;
  840. X                if (argc-i < 2)
  841. X                    stopit ("Missing arguments");
  842. X                volser = argv[++i];
  843. X                owner = argv[++i];
  844. X                writevol ();
  845. X                break;
  846. X
  847. X            case 'x':    /* extract files from tape */
  848. X            case 'X':
  849. X                if (operation != NOOPER)
  850. X                    stopit ("Can't redefine operation");
  851. X                operation = READTAPE;
  852. X                readvol1 ();
  853. X                if ((i+1) == argc)
  854. X                {    /* last option, read all files */
  855. X                    readall ();
  856. X                    exit (0);
  857. X                }
  858. X                /* otherwise, read files as names provided */
  859. X                break;
  860. X
  861. X            case 'l':    /* list files on tape */
  862. X            case 'L':
  863. X                if (operation != NOOPER)
  864. X                    stopit ("Can't redefine operation");
  865. X                operation = LISTTAPE;
  866. X                readvol1 ();
  867. X                listtape ();
  868. X                exit (0);
  869. X
  870. X            case 't':    /* specify tape drive */
  871. X            case 'T':    /* must be a raw device file */
  872. X                tapename = argv[++i];
  873. X                break;
  874. X
  875. X            case 's':    /* silent mode */
  876. X            case 'S':
  877. X                verbose = 0;
  878. X                break;
  879. X
  880. X            case 'D':    /* debug flag - see abort handling */
  881. X                debug++;
  882. X                break;
  883. X
  884. X            case 'h':
  885. X            case 'H':    /* online help */
  886. X                helpme ();
  887. X                exit (0);
  888. X
  889. X            default:
  890. X                err ("bad flag - ignored");
  891. X            }
  892. X        }
  893. X        else
  894. X        {    /* handle file argument */
  895. X            if (operation == NOOPER)
  896. X                stopit ("No operation [l/c/x] selected");
  897. X            else if (operation == CREATAPE)
  898. X                writefile (argv[i]);
  899. X            else if (operation == READTAPE)
  900. X                readfile (argv[i]);
  901. X            else
  902. X                stopit ("??");
  903. X        }
  904. X    }
  905. X    if (operation == CREATAPE)
  906. X    {
  907. X        tapewtm ();
  908. X        tapewtm ();
  909. X        taperew ();
  910. X    }
  911. X    else if (operation == NOOPER)
  912. X    {
  913. X        helpme ();
  914. X    }
  915. }
  916. X
  917. X
  918. numopt (cp)
  919. X    char *cp;
  920. {
  921. X    if (cp == 0)
  922. X        return (0);
  923. X    else
  924. X        return (atoi(cp));
  925. }
  926. X
  927. X
  928. helpme ()
  929. {
  930. X    printf ("\nANSI or IBM/OS standard labelled tape processing:\n\n");
  931. X    printf ("  slt -l            list contents of tape\n");
  932. X    printf ("  slt -x a b c            extract 3 files as a, b, c\n");
  933. X    printf ("  slt -x            extract all files\n");
  934. X    printf ("  slt -c volser owner a b c    create new tape\n");
  935. X    printf ("  slt -t rawdev [-l|-c|-x]...    use tape drive rawdev\n\n");
  936. X    printf ("  specifying -i as first flag selects IBM OS/VS format\n\n");
  937. X    printf ("read manual page for advanced usage!\n");
  938. }
  939. X
  940. X
  941. /***********************************************************************
  942. ***    listing file properties
  943. ***********************************************************************/
  944. X
  945. listtape ()
  946. {
  947. X    printf (
  948. "\nseq# filename           creat expir  blocks  f blks  lrecl  created by\n");
  949. X    printf (
  950. X  "----------------------------------------------------------------------\n");
  951. X    for (;;)
  952. X    {
  953. X        /* read hdr labels -- will finish on EOT */
  954. X        readhdr (1);
  955. X        if (debug)
  956. X            printf ("\n--- reading HDR1/2:\n%80s\n%80s\n",
  957. X                hdr1lab, hdr2lab);
  958. X        /* skip data blocks -- to next tape mark */
  959. X        tapefsf ();
  960. X        if (debug)
  961. X            printf ("--- forward skip file\n");
  962. X        /* read eof labels and report */
  963. X        readhdr (0);
  964. X        if (debug)
  965. X            printf ("--- reading EOF1/2:\n%80s\n%80s\n\n",
  966. X                hdr1lab, hdr2lab);
  967. X        listfile ();
  968. X    }
  969. }
  970. X
  971. X
  972. listfile ()
  973. {
  974. X    /* data set seq number and data set name (filename) */
  975. X    lstlab (hdr1lab, DSSNPOS, DSSNLEN, " ");
  976. X    lstlab (hdr1lab, DSNPOS, DSNLEN, " ");
  977. X
  978. X    /* creation and expiration date (leading blank part of field) */
  979. X    lstlab (hdr1lab, CDPOS, CDLEN, "");
  980. X    lstlab (hdr1lab, EDPOS, EDLEN, "  ");
  981. X
  982. X    /* number of blocks */
  983. X    lstlab (hdr1lab, BCPOS, BCLEN, "  ");
  984. X
  985. X    /* format, blocksize, record length */
  986. X    lstlab (hdr2lab, RFPOS, RFLEN, " ");
  987. X    lstlab (hdr2lab, BLPOS, BLLEN, " ");
  988. X    lstlab (hdr2lab, RLPOS, RLLEN, "  ");
  989. X    
  990. X    /* created by */
  991. X    lstlab (hdr1lab, SCPOS, SCLEN, "\n");
  992. }
  993. X
  994. X
  995. /*************************************************************************
  996. ***    reading and writing of files
  997. *************************************************************************/
  998. X
  999. readfile (ufn)
  1000. X    char *ufn;
  1001. {
  1002. X    int format, bcount;
  1003. X    char *unixfn;
  1004. X    char *getlfnlc(), *getlfnuc();
  1005. X
  1006. X    /* next file header labels -- will finish on EOT */
  1007. X    readhdr (1);
  1008. X
  1009. X    /* select tape format */
  1010. X    recfm = getlrecfm();
  1011. X    
  1012. X    if (standard == ANSISTD)
  1013. X    {        /* encode both format and direction of transfer */
  1014. X        if (recfm == 'F')
  1015. X            format = 'f';
  1016. X        else if (recfm == 'D')
  1017. X            format = 'd';
  1018. X        else
  1019. X            format = 'u';
  1020. X    } else
  1021. X    {
  1022. X        if (recfm == 'V')
  1023. X            format = 'v';
  1024. X        else format = 'a';
  1025. X    }
  1026. X
  1027. X    fseqno++;
  1028. X    if (verbose)
  1029. X        printf ("%d.  %s  ==>  ", fseqno, getlfnuc());
  1030. X
  1031. X    if (ufn == 0)
  1032. X        /* use name on tape */
  1033. X        unixfn = getlfnlc ();
  1034. X    else
  1035. X        /* use name provided */
  1036. X        unixfn = ufn;
  1037. X
  1038. X    if (verbose)
  1039. X        printf ("%s", unixfn);
  1040. X
  1041. X    if ((diskfid = creat (unixfn, 0644)) < 0)
  1042. X        ioabort ("Can't create Unix file\n");
  1043. X
  1044. X    blksize = getlblks();
  1045. X    blksize +=  (blksize % 2);    /* must be even - stupid controller */
  1046. X
  1047. X    bcount = movefil (tapefid, diskfid, blksize, UBLKS,
  1048. X            getllrecl(), format, 0);
  1049. X
  1050. X    if (verbose)
  1051. X        printf ("  (%d tape blocks)\n", bcount);
  1052. X
  1053. X    close(diskfid);
  1054. X
  1055. X    /* read and forget eof labels */
  1056. X    readhdr (0);
  1057. X    return (1);
  1058. }
  1059. X
  1060. X
  1061. readall ()
  1062. {
  1063. X    printf ("Extracting all files on tape...\n");
  1064. X    for (;;)
  1065. X        readfile ((char *)0);
  1066. }
  1067. X
  1068. X
  1069. writefile (ufn)
  1070. X    char *ufn;
  1071. {
  1072. X    int format, bsi;
  1073. X    int bcount;
  1074. X    char *unixname;
  1075. X    char *leafname(), *getlfnuc();
  1076. X
  1077. X    if (standard == ANSISTD)
  1078. X    {        /* encode both format and direction of transfer */
  1079. X        if (recfm == FIXED)
  1080. X            format = 'F';
  1081. X        else if (recfm == VAR)
  1082. X        {
  1083. X            recfm = AVAR;
  1084. X            format = 'D';
  1085. X        }
  1086. X        else if (recfm == AVAR)
  1087. X            format = 'D';
  1088. X        else format = 0;
  1089. X    }
  1090. X    else if (recfm == VAR)
  1091. X            format = 'V';
  1092. X    else format = 'E';
  1093. X
  1094. X    if (fchange)
  1095. X    {
  1096. X        fchange = 0;
  1097. X        if (verbose)
  1098. X            tellform ();
  1099. X        if (!formatok ())
  1100. X        {
  1101. X            printf ("file %s ignored\n\n", ufn);
  1102. X            return;
  1103. X        }
  1104. X    }
  1105. X
  1106. X    /* strip directories from unix pathname */
  1107. X    unixname = leafname (ufn);
  1108. X
  1109. X    if ((diskfid = open (ufn, 0)) < 0)
  1110. X    {
  1111. X        fprintf (stderr, "Can't open file \"%s\" -- ignored\n", ufn);
  1112. X        return;
  1113. X    }
  1114. X
  1115. X    /* write header labels */
  1116. X    fseqno++;
  1117. X    mkhdr1 (unixname, fseqno, 0, 1);
  1118. X    mkhdr2 (1);
  1119. X    if (verbose)
  1120. X        printf ("%d.  %s  ==>  %s  ", fseqno, ufn, getlfnuc());
  1121. X    writehdrs ();
  1122. X
  1123. X    /* set input blocksize */
  1124. X    if ((standard == ANSISTD) && ((blksize % 512) == 0))
  1125. X        bsi = blksize;
  1126. X    else bsi = UBLKS;
  1127. X
  1128. X    /* write data blocks */
  1129. X    truncated = 0;
  1130. X    bcount = movefil (diskfid, tapefid, bsi, blksize, lrecl, format, 0);
  1131. X    tapewtm ();
  1132. X
  1133. X    close (diskfid);
  1134. X
  1135. X    if (bcount == -1)
  1136. X    {
  1137. X        tapewtm ();
  1138. X        taperew ();
  1139. X        exit (-1);
  1140. X    }
  1141. X    else
  1142. X    {
  1143. X        /* write eof labels */
  1144. X        mkhdr1 (unixname, fseqno, bcount, 0);
  1145. X        mkhdr2 (0);
  1146. X        writehdrs ();
  1147. X
  1148. X        if (debug)
  1149. X        {    printf (" written to\n");
  1150. X            listfile ();
  1151. X            printf ("\n");
  1152. X        }
  1153. X        else if (verbose)
  1154. X            printf (" (%d tape blocks)\n", bcount);
  1155. X
  1156. X        if (truncated)
  1157. X        {
  1158. X            printf ("**** %d truncated input records", truncated);
  1159. X            if (verbose || debug)
  1160. X                printf ("\n");
  1161. X            else
  1162. X                printf (" for file %s\n", ufn);
  1163. X        }
  1164. X
  1165. X        return(1);
  1166. X    }
  1167. }
  1168. X
  1169. X
  1170. formatok ()
  1171. {
  1172. X    if (recfm == FIXED)
  1173. X    {
  1174. X        if ( lrecl > 0 && blksize % lrecl)
  1175. X            stopit ("Blocksize must be multiple of record length");
  1176. X    }
  1177. X    if (recfm == VAR)
  1178. X    {
  1179. X        if (standard == ANSISTD)
  1180. X        {
  1181. X            if (blksize < 18)
  1182. X            {
  1183. X                err ("Blocksize must at least be 18 bytes");
  1184. X                blksize = 18;
  1185. X                return (0);
  1186. X            }
  1187. X            if (blksize > 2048)
  1188. X                err ("Blocksize should be upto 2048 bytes");
  1189. X        }
  1190. X        if ((blksize - lrecl) < 4)
  1191. X            stopit (
  1192. "Blocksize must be at least 4 bytes greater than record length");
  1193. X        if (lrecl < 5) 
  1194. X            stopit ("Record length too small for recfm=V");
  1195. X    }
  1196. X    return(1);
  1197. }
  1198. X
  1199. X
  1200. tellform ()
  1201. {
  1202. X    printf ("\nBlock size %d, record length %d, record format %c\n",
  1203. X        blksize, lrecl, (recfm & 0337));
  1204. }
  1205. X
  1206. X
  1207. char *
  1208. leafname (path)
  1209. X    char *path;
  1210. {
  1211. X    register char *p, *q;
  1212. X
  1213. X    p = q = path;
  1214. X    while (*p != '\0')
  1215. X        if (*p++ == '/')
  1216. X            q = p;
  1217. X    return (q);
  1218. }
  1219. X
  1220. X
  1221. /*************************************************************************
  1222. ***    reading / writing tape labels
  1223. *************************************************************************/
  1224. X
  1225. readvol1 ()
  1226. {
  1227. X    char *getlvser(), *getlown();
  1228. X
  1229. X    tapeopen ();
  1230. X    if (!readlab (vollab))
  1231. X        ioabort ("Reading volume label");
  1232. X    if (isvol ())
  1233. X    {
  1234. X        printf ("Volume serial number \"%s\",  ", getlvser ());
  1235. X        printf ("tape owner \"%s\", ", getlown());
  1236. X        liststd ();
  1237. X    } else {
  1238. X        if (debug)
  1239. X            printf ("Bad volume label <%s>\n", vollab);
  1240. X        stopit ("Bad VOL1 label\n");
  1241. X    }
  1242. }
  1243. X
  1244. X
  1245. liststd ()
  1246. {
  1247. X    char *getlstd();
  1248. X
  1249. X    if (standard == ANSISTD)
  1250. X        printf ("ANSI X3.27 level %s label.\n", getlstd());
  1251. X    else
  1252. X        printf ("IBM std label.\n");
  1253. }
  1254. X
  1255. X
  1256. readhdr (hdrflag)
  1257. X    int hdrflag;
  1258. {
  1259. X    if (!readlab (hdr1lab) || !readlab (hdr2lab))
  1260. X    {
  1261. X        printf ("EOT\n");    /* eof == end of tape reached */
  1262. X        exit (0);
  1263. X    }
  1264. X    tapefsf ();            /* skip user labels and tape mark */
  1265. X    if (hdrflag)            /* header ? */
  1266. X    {
  1267. X        if (ishdr (hdr1lab) && ishdr (hdr2lab))
  1268. X            return;
  1269. X        if (debug)
  1270. X        {
  1271. X            printf ("Bad file header label(s):\n");
  1272. X            printf ("*** HDR1 ***\n%80s\n", hdr1lab);
  1273. X            printf ("*** HDR2 ***\n%80s\n", hdr2lab);
  1274. X        }
  1275. X        stopit ("Missing or badly formed header label");
  1276. X    }
  1277. X    else
  1278. X    {
  1279. X        if (iseof (hdr1lab) && iseof (hdr2lab))
  1280. X            return;
  1281. X        if (debug)
  1282. X        {
  1283. X            printf ("Bad end of file label(s):\n");
  1284. X            printf ("*** EOF1 ***\n%80s\n", hdr1lab);
  1285. X            printf ("*** EOF2 ***\n%80s\n", hdr2lab);
  1286. X        }
  1287. X        stopit ("Missing or badly formed eof label");
  1288. X    }
  1289. }
  1290. X
  1291. X
  1292. writevol ()
  1293. {
  1294. X    tapecreat ();
  1295. X    upcase (volser);
  1296. X    upcase (owner);
  1297. X    mkvol1 ();
  1298. X    writelab (vollab);
  1299. X    printf ("Volume initialized, volser \"%s\", owner \"%s\", ",
  1300. X        volser, owner);
  1301. X    liststd ();
  1302. }
  1303. X
  1304. X
  1305. writehdrs ()
  1306. {
  1307. X    writelab (hdr1lab);
  1308. X    writelab (hdr2lab);
  1309. X    tapewtm ();
  1310. }
  1311. X
  1312. X
  1313. /*************************************************************************
  1314. ***    label composition
  1315. *************************************************************************/
  1316. X
  1317. mkvol1 ()
  1318. {
  1319. X    clearlab (vollab, 0, LABLEN);
  1320. X
  1321. X    /* label identifier */
  1322. X    putlab (vollab, LIDPOS, LIDLEN, "VOL1");
  1323. X
  1324. X    /* reserved field */
  1325. X    if (standard == IBMSTD)
  1326. X        putlab (vollab, VR1POS, 1, "0");
  1327. X
  1328. X    /* volume serial number */
  1329. X    putlab (vollab, SERPOS, SERLEN, volser);
  1330. X
  1331. X    /* owner of tape */
  1332. X    putlab (vollab, OWNPOS, OWNLEN, owner);
  1333. X
  1334. X    /* label standard level */
  1335. X    if (standard == ANSISTD)
  1336. X        putlab (vollab, LSLPOS, 1, stdlevel);
  1337. }
  1338. X
  1339. X
  1340. mkhdr1 (name, number, bcount, hdr)
  1341. X    char name[];        /* data det name */
  1342. X    int number;        /* data set sequence number on tape */
  1343. X    int bcount;        /* block count */
  1344. X    int hdr;        /* flag: 1 for HDR1, 0 for EOF1 */
  1345. {
  1346. X    struct tm *convtime;    /* converted time; see upm, ctime(3) */
  1347. X    int year, day;
  1348. X
  1349. X    clearlab (hdr1lab, 0, LABLEN);
  1350. X
  1351. X    /* label identifier */
  1352. X    if (hdr)
  1353. X        putlab (hdr1lab, LIDPOS, LIDLEN, "HDR1");
  1354. X    else
  1355. X        putlab (hdr1lab, LIDPOS, LIDLEN, "EOF1");
  1356. X
  1357. X    /* data set identifier */
  1358. X    putlab (hdr1lab, DSNPOS, DSNLEN, name);
  1359. X    
  1360. X    /* data set serial number */
  1361. X    putlab (hdr1lab, DSSRPOS, DSSRLEN, volser);
  1362. X
  1363. X    /* volume sequence number */
  1364. X    putlab (hdr1lab, VSSNPOS, VSSNLEN, "0001");
  1365. X
  1366. X    /* data set sequence number */
  1367. X    putlabint (hdr1lab, DSSNPOS, DSSNLEN, number);
  1368. X
  1369. X    /* generation number */
  1370. X    putlab (hdr1lab, GENNPOS, GENNLEN, "0001");
  1371. X
  1372. X    /* version number of generation */
  1373. X    putlab (hdr1lab, GVNPOS, GVNLEN, "00");
  1374. X
  1375. X    /* creation date, julian date form (year, day in year) */
  1376. X    convtime = gmtime (&clock);
  1377. X    year = convtime->tm_year;
  1378. X    day = convtime->tm_yday;
  1379. X    putlabint (hdr1lab, CDPOS+1, 2, year);
  1380. X    putlabint (hdr1lab, CDPOS+3, 3, day);
  1381. X
  1382. X    /* expiration date */
  1383. X    putlabint (hdr1lab, EDPOS+1, 2, year);
  1384. X    putlabint (hdr1lab, EDPOS+3, 3, day);
  1385. X
  1386. X    /* data set security */
  1387. X    putlab (hdr1lab, DSSPOS, 1," ");
  1388. X
  1389. X    /* block count */
  1390. X    if (hdr)
  1391. X        putlabint (hdr1lab, BCPOS, BCLEN, 0);
  1392. X    else
  1393. X        putlabint (hdr1lab, BCPOS, BCLEN, bcount);
  1394. X
  1395. X    /* system code */
  1396. X    putlab (hdr1lab, SCPOS, SCLEN, SYSID);
  1397. }
  1398. X
  1399. X
  1400. mkhdr2 (hdr)
  1401. X    int  hdr;        /* header flag, see mkhdr1 */
  1402. {
  1403. X    clearlab (hdr2lab, 0, LABLEN);
  1404. X
  1405. X    /* label identifier */
  1406. X    if (hdr)
  1407. X        putlab (hdr2lab, LIDPOS, LIDLEN, "HDR2");
  1408. X    else
  1409. X        putlab (hdr2lab, LIDPOS, LIDLEN, "EOF2");
  1410. X
  1411. X    /* record format */
  1412. X    if (recfm == FIXED)
  1413. X        putlab (hdr2lab, RFPOS, 1, "F");
  1414. X    else if (recfm == AVAR)
  1415. X        putlab (hdr2lab, RFPOS, 1, "D");
  1416. X    else if (recfm == VAR)
  1417. X        putlab (hdr2lab, RFPOS, 1, "V");
  1418. X    else
  1419. X        putlab (hdr2lab, RFPOS, 1, "U");
  1420. X
  1421. X    /* block length */
  1422. X    putlabint (hdr2lab, BLPOS, BLLEN, blksize);
  1423. X
  1424. X    /* record length */
  1425. X    putlabint (hdr2lab, RLPOS, RLLEN, lrecl);
  1426. X
  1427. X    if (standard == IBMSTD)
  1428. X    {
  1429. X        /* tape density == 1600 bpi */
  1430. X        putlab (hdr2lab, TDPOS, 1, "3");
  1431. X    
  1432. X        /* data set position */
  1433. X        putlab (hdr2lab, DSPPOS, 1, "0");
  1434. X    
  1435. X        /* job/step identification */
  1436. X        putlab (hdr2lab, JIPOS, JILEN, "STDTAPE /SLT");
  1437. X    
  1438. X        /* tape recording technique */
  1439. X        putlab (hdr2lab, TRTPOS, TRTLEN, "  ");
  1440. X    
  1441. X        /* printer control characters */
  1442. X        putlab (hdr2lab, PCCPOS, 1, " ");
  1443. X    
  1444. X        /* reserved 1 -- must be blank*/
  1445. X        putlab (hdr2lab, R1POS, 1, " ");
  1446. X    
  1447. X        /* block attributes */
  1448. X        if (blksize != lrecl)
  1449. X            putlab (hdr2lab, BAPOS, 1, "B");
  1450. X    }
  1451. X    else if (standard == ANSISTD)
  1452. X    {
  1453. X        /* buffer offset */
  1454. X        putlab (hdr2lab, BOPOS, 2, "00");
  1455. X    }
  1456. }
  1457. X
  1458. X
  1459. /*************************************************************************
  1460. ***    label field access
  1461. *************************************************************************/
  1462. X
  1463. clearlab (label, start, leng)
  1464. X    char label[];
  1465. X    int start, leng;
  1466. {
  1467. X    register int i;
  1468. X    for (i = start; i < start+leng; i++)
  1469. X        label[i] = ' ';
  1470. }
  1471. X
  1472. X
  1473. putlab (label, pos, maxlen, string)
  1474. X    char label[];
  1475. X    int pos, maxlen;
  1476. X    char string[];
  1477. {
  1478. X    register int i;
  1479. X    register char c;
  1480. X    for (i = 0; i < maxlen && (c = *string++) != '\0'; i++)
  1481. X    {
  1482. X        if ( c >= 'a' && c <= 'z')    /* label in uppercase */
  1483. X            c &= ~040;
  1484. X        label[pos+i] = c;
  1485. X    }
  1486. }
  1487. X
  1488. X
  1489. putlabint (label, pos, len, num)
  1490. X    char *label;
  1491. X    int pos, len, num;
  1492. {
  1493. X    /* put integer with length 'len' to 'pos' in 'label'
  1494. X     * insert leading zeros where needed */
  1495. X    int i, rest;
  1496. X
  1497. X    rest = num;
  1498. X    for (i=len+pos-1; i >= pos; i --)
  1499. X    {
  1500. X        label[i] = (rest % 10) + '0';
  1501. X        rest = rest / 10;
  1502. X    }
  1503. }
  1504. X
  1505. X
  1506. lstlab (label, pos, length, trailer)
  1507. X    char *label, *trailer;
  1508. X    int pos, length;
  1509. {
  1510. X    char *p;
  1511. X
  1512. X    p = &label[pos];
  1513. X    while (length--)
  1514. X        putchar (*p++);
  1515. X    printf ("%s", trailer);
  1516. }
  1517. X
  1518. X
  1519. char *
  1520. getlab (label, pos, length, lowcase)
  1521. X    char *label;
  1522. X    int pos, length, lowcase;
  1523. {
  1524. X    register int i;
  1525. X    register char c;
  1526. X
  1527. X    for ( i=0; i < length && (c = label[pos + i]) != ' '; i++)
  1528. X    {
  1529. X        if (lowcase  &&  c >= 'A' && c <= 'Z')
  1530. X            temp[i] = c + 'a' - 'A';
  1531. X        else
  1532. X            temp[i] = c;
  1533. X    }
  1534. X    temp[i] = '\0';
  1535. X    return (temp);
  1536. }
  1537. X
  1538. X
  1539. getlabint (label, pos, len)
  1540. X    char *label;
  1541. X    int pos, len;
  1542. {
  1543. X    /* read an integer from a label */
  1544. X    register int i, num;
  1545. X
  1546. X    num = 0;
  1547. X    for (i = 0; i < len; i++)
  1548. X        num = num * 10 + label[pos+i] - '0';
  1549. X    return (num);
  1550. }
  1551. X
  1552. X
  1553. getlabchar (label, pos)
  1554. X    char *label;
  1555. X    int pos;
  1556. {
  1557. X    return (label[pos]);
  1558. }
  1559. X
  1560. X
  1561. /*************************************************************************
  1562. ***    specific label field access routines
  1563. *************************************************************************/
  1564. X
  1565. char *
  1566. getlvser ()
  1567. {
  1568. X    return (getlab (vollab, SERPOS, SERLEN, 0));
  1569. }
  1570. X
  1571. char *
  1572. getlown ()
  1573. {
  1574. X    return (getlab (vollab, OWNPOS, OWNLEN, 0));
  1575. }
  1576. X
  1577. char *
  1578. getlstd ()
  1579. {
  1580. X    return (getlab (vollab, LSLPOS, LSLLEN, 0));
  1581. }
  1582. X
  1583. char *
  1584. getlfnuc ()
  1585. {
  1586. X    return (getlab (hdr1lab, DSNPOS, DSNLEN, 0));
  1587. }
  1588. X
  1589. char *
  1590. getlfnlc ()
  1591. {
  1592. X    return (getlab (hdr1lab, DSNPOS, DSNLEN, 1));
  1593. }
  1594. X
  1595. getlblks ()
  1596. {
  1597. X    return (getlabint (hdr2lab, BLPOS, BLLEN));
  1598. }
  1599. X
  1600. getllrecl ()
  1601. {
  1602. X    return (getlabint (hdr2lab, RLPOS, RLLEN));
  1603. }
  1604. X
  1605. getlrecfm ()
  1606. {
  1607. X    return (getlabchar (hdr2lab, RFPOS) & 0337);
  1608. }
  1609. X
  1610. getldssn ()
  1611. {
  1612. X    return (getlabint (hdr1lab, DSSNPOS, DSSNLEN));
  1613. }
  1614. X
  1615. X
  1616. /*************************************************************************
  1617. ***    reading / writing tape labels
  1618. *************************************************************************/
  1619. X
  1620. readlab (lab)
  1621. X    char *lab;
  1622. {
  1623. X    int r;
  1624. X    char *strncpy ();
  1625. X    r= read (tapefid, temp, MAXLABLEN);
  1626. X        if (r >= LABLEN)
  1627. X    {
  1628. X        strncpy (lab, temp, LABLEN);
  1629. X        if (standard == IBMSTD)
  1630. X            toascii (lab, LABLEN);
  1631. X        return (1);
  1632. X    }
  1633. X    else if (r < 0)
  1634. X    {    /* error */
  1635. X        ioabort ("Can't read tape label");
  1636. X        /* never come here, but please lint */
  1637. X        return (0);
  1638. X    }
  1639. X    else return (0);
  1640. }
  1641. X
  1642. writelab (lab)
  1643. X    char *lab;
  1644. {
  1645. X    int w;
  1646. X
  1647. X    if (standard == IBMSTD)
  1648. X        toebcdic (lab, LABLEN);
  1649. X
  1650. X    w = write (tapefid, lab, LABLEN);
  1651. X    if (w < 0)
  1652. X        ioabort ("Can't write tape label");
  1653. }
  1654. X
  1655. X
  1656. /*************************************************************************
  1657. ***    label type checking
  1658. *************************************************************************/
  1659. X
  1660. isvol ()
  1661. {
  1662. X    return (cmpstr ("VOL1", getlab (vollab, LIDPOS, LIDLEN, 0)) == 0);
  1663. }
  1664. X
  1665. ishdr (lab)
  1666. X    char *lab;
  1667. {
  1668. X    return (cmpstr ("HDR", getlab (lab, LIDPOS, 3, 0)) == 0);
  1669. }
  1670. X
  1671. iseof (lab)
  1672. X    char *lab;
  1673. {
  1674. X    if (cmpstr ("EOF", getlab (lab, LIDPOS, 3, 0)) == 0)
  1675. X        return (1);
  1676. X    if (cmpstr ("EOV", getlab (lab, LIDPOS, 3, 0)) == 0)
  1677. X        return (1);
  1678. X    else return (0);
  1679. }
  1680. X
  1681. X
  1682. /*************************************************************************
  1683. ***    moving the data -- the actual work
  1684. *************************************************************************/
  1685. X
  1686. #define    LCASE    01
  1687. #define    UCASE    02
  1688. #define PAD    020    /* pad input records to ibs */
  1689. X
  1690. int    cflag;
  1691. int    fflag;
  1692. int    ibf;        /* input file descriptor */
  1693. int    obf;        /* output file descriptor */
  1694. int    ibs;        /* input buffer size */
  1695. int    obs;        /* output buffer size */
  1696. int    cbs;        /* conversion buffer size */
  1697. char    *ibuf;        /* input buffer */
  1698. char    *obuf;        /* output buffer */
  1699. char     *rbuf;
  1700. int    ibc;        /* input block count (number of chars read) */
  1701. int    obc;        /* output block count (number of chars written) */
  1702. int    cbc;
  1703. int    lr;
  1704. int    nifr;        /* number of filled input blocks */
  1705. int    nipr;        /* number of partially filled input blocks */
  1706. int    nofr;        /* number of filled output blocks */
  1707. int    nopr;        /* number of partially filled output blocks */
  1708. char    *op;
  1709. char    *rp;        /* pointer into record buffer (for var recs) */
  1710. int    nspace;
  1711. X
  1712. char     *sbrk();    /* sbrk() returns ptr to buffer */
  1713. X
  1714. X
  1715. movefil (infile, outfile, pibs, pobs, pcbs, code, cas)
  1716. X    int    infile, outfile;    /* filedescriptors */
  1717. X    int    pibs, pobs, pcbs;    /* block sizes */
  1718. X    int    code, cas;        /* translations */
  1719. {
  1720. X    register (*conv)();
  1721. X    register char *ip;
  1722. X    register c;
  1723. X    int fixibm(), unfixibm(), null (), cnull();
  1724. X        int fix(), unfix();
  1725. X    int var(), unvar();
  1726. X    int varibm(), unvaribm();
  1727. X    int a;
  1728. X
  1729. X    /* globalize parms -- artefact of old pgm */
  1730. X    ibf = infile;
  1731. X    obf = outfile;
  1732. X    ibs = pibs;
  1733. X    obs = pobs;
  1734. X    cbs = pcbs;
  1735. X    conv = null;
  1736. X    fflag = 0;
  1737. X    cflag = 0;
  1738. X
  1739. X    nipr = 0; nifr = 0; nopr = 0; nofr = 0; nspace = 0;
  1740. X
  1741. X    /* translations */
  1742. X    switch (code)
  1743. X    {
  1744. X        case 'E': conv = fixibm; break;        /* to tape */
  1745. X        case 'a': conv = unfixibm; break;    /* from tape */
  1746. X        case 'F': conv = fix; break;        /* to tape */
  1747. X        case 'f': conv = unfix; break;         /* from tape */
  1748. X        case 'V': conv = varibm; break;        /* to tape */
  1749. X        case 'v': conv = unvaribm; break;    /* from tape */
  1750. X        case 'D': conv = var; break;        /* to tape */
  1751. X        case 'd': conv = unvar; break;        /* from tape */
  1752. X    }
  1753. X    if (cas == 'l')
  1754. X        cflag |= LCASE;
  1755. X    if (cas == 'u')
  1756. X        cflag |= UCASE;
  1757. X
  1758. X    if (conv == null && cflag&(LCASE|UCASE))
  1759. X        conv = cnull;
  1760. X    if (ibs == 0)
  1761. X        ibs = UBLKS;
  1762. X    if (obs == 0)
  1763. X        obs = UBLKS;
  1764. X    if (ibs == obs && conv == null)
  1765. X        fflag ++;
  1766. X
  1767. X    /* get buffers */
  1768. X    ibuf = sbrk (ibs);
  1769. X    if (fflag)
  1770. X    {
  1771. X        obuf = ibuf;
  1772. X        rbuf = ibuf;
  1773. X    }
  1774. X    else
  1775. X    {
  1776. X        obuf = sbrk (obs);
  1777. X        if (code == 'D' || code == 'V' )
  1778. X            rbuf = sbrk (cbs);
  1779. X        else rbuf=obuf;
  1780. X    }
  1781. X    if ((ibuf == (caddr_t) -1)
  1782. X    || (obuf == (caddr_t) -1)
  1783. X    || (rbuf == (caddr_t) -1))
  1784. X        stopit ("Insufficient memory for buffers");
  1785. X    ibc = 0;
  1786. X    obc = 0;
  1787. X    cbc = 0;
  1788. X    lr = 0;
  1789. X    op = obuf;
  1790. X
  1791. X    if (conv == varibm)
  1792. X    {
  1793. X        /* reserve block length field */
  1794. X        op += 4;
  1795. X        obc = 4;
  1796. X        /* reserve record length field */
  1797. X        rp = rbuf + 4;
  1798. X        cbc = 4;
  1799. X    }
  1800. X    if (conv == var )
  1801. X    {
  1802. X        /* reserve record length field */
  1803. X        rp = rbuf + 4;
  1804. X        cbc = 4;
  1805. X    }
  1806. X    rp = rbuf+4;
  1807. X
  1808. X
  1809. X    /* now do the job */
  1810. loop:
  1811. X    if (ibc-- == 0)
  1812. X    {
  1813. X        /* read a block */
  1814. X        ibc = read (ibf, ibuf, ibs);
  1815. X        if (ibc == -1)            /* read error */
  1816. X        {
  1817. X            perror ("read");
  1818. X            flsh ();
  1819. X            exit (-1);
  1820. X        }
  1821. X        if (ibc == 0)            /* eof */
  1822. X        {
  1823. X            if (conv == var)
  1824. X            {            /* pad buffer with '^' */
  1825. X                a = obs - obc;
  1826. X                while ( a--)
  1827. X                    null ('^');
  1828. X            }
  1829. X            if (conv == varibm)
  1830. X            {
  1831. X                /* insert block length */
  1832. X                putlength (obuf,obc);
  1833. X    
  1834. X                a = obs - obc;
  1835. X                while (a--)
  1836. X                    null (0);
  1837. X            }
  1838. X            flsh ();
  1839. X            brk (ibuf);
  1840. X            return (nopr+nofr);
  1841. X        }
  1842. X        if (ibc != ibs)            /* partial block read */
  1843. X        {
  1844. X            nipr++;
  1845. X            if ( cflag & PAD )
  1846. X            {
  1847. X                /* pad input buffer to ibs with 0's */
  1848. X                for (ip = &ibuf[ibs]; ip > &ibuf[ibc]; )
  1849. X                    *--ip = '\0';
  1850. X                ibc = ibs;
  1851. X            }
  1852. X        } else
  1853. X            nifr++;
  1854. X
  1855. X        ip = ibuf;
  1856. X        if (conv == unvaribm)
  1857. X        {
  1858. X            /* get block length from input block ;
  1859. X            ** must built ibc explicitly in two assignments,
  1860. X            ** otherwise there might be reordering of
  1861. X            ** expression by c compiler (lint saw it...) */
  1862. X            ibc =  ((*ip++) << 8 );
  1863. X            ibc |= ((*ip++) & 0377) ;
  1864. X            ip++; ip++;
  1865. X            ibc -= 4;    /* account for length field */
  1866. X        }
  1867. X        ip = ibuf;
  1868. X        if (conv == unvaribm)
  1869. X            ip = ip + 4;
  1870. X
  1871. X        /* no conversions to be done ? */
  1872. X        if (fflag)
  1873. X        {
  1874. X            obc = ibc;
  1875. X            flsh ();
  1876. X            ibc = 0;
  1877. X        }
  1878. X        goto loop;
  1879. X    }
  1880. X    c = 0;
  1881. X    c |= *ip++;
  1882. X    (*conv)(c);
  1883. X    goto loop;
  1884. }
  1885. X
  1886. flsh ()
  1887. {
  1888. X    if (obc)
  1889. X    {
  1890. X        if (obc == obs)
  1891. X            nofr++;
  1892. X        else
  1893. X        {
  1894. X            nopr++;
  1895. X            if (obc & 01 && obf == tapefid)
  1896. X            {
  1897. X                /* prevent writing out uneven number of bytes
  1898. X                   tapeunit does not like it */
  1899. X                *op = 0;
  1900. X                obc ++ ;
  1901. X            }
  1902. X        }
  1903. X        if (write (obf, obuf, obc) != obc)
  1904. X            ioabort ("write");
  1905. X        obc = 0;
  1906. X    }
  1907. }
  1908. X
  1909. X
  1910. cnull (cc)
  1911. {
  1912. X    register c;
  1913. X
  1914. X    c = cc;
  1915. X    if (cflag&UCASE && c>='a' && c<='z')
  1916. X        c += 'A'-'a';
  1917. X    if (cflag&LCASE && c>='A' && c<='Z')
  1918. X        c += 'a'-'A';
  1919. X    null (c);
  1920. }
  1921. X
  1922. null (c)
  1923. {
  1924. X    *op = c;
  1925. X    op++;
  1926. X    if (++obc >= obs)
  1927. X    {
  1928. X        flsh ();
  1929. X        op = obuf;
  1930. X    }
  1931. }
  1932. X
  1933. X
  1934. /*    unfixibm - convert fixed format records from tape to
  1935. **    unix format and translate them to ascii
  1936. **    throw away trailing blanks
  1937. **    insert newline character at end of line
  1938. */
  1939. X
  1940. unfixibm (cc)
  1941. {
  1942. X    register c;
  1943. X
  1944. X    c = 0;
  1945. X    c |= etoa[cc & 0377];
  1946. X    if (cbs == 0)
  1947. X    {
  1948. X        cnull (c);
  1949. X        return;
  1950. X    }
  1951. X    if (c == ' ')
  1952. X        nspace++;
  1953. X    else
  1954. X    {
  1955. X        while (nspace > 0)
  1956. X        {
  1957. X            null (' ');
  1958. X            nspace--;
  1959. X        }
  1960. X        cnull (c);
  1961. X    }
  1962. X    if (++cbc >= cbs)
  1963. X    {
  1964. X        null ('\n');
  1965. X        cbc = 0;
  1966. X        nspace = 0;
  1967. X    }
  1968. }
  1969. X
  1970. X
  1971. /*    unfix - convert fixed record format records from tape
  1972. **    to unix format (no code conversion)
  1973. **    throw away trailing blanks
  1974. **    insert newline character at end of record
  1975. */
  1976. X
  1977. unfix (cc)
  1978. {
  1979. X    register c;
  1980. X
  1981. X    c = cc;
  1982. X    if (cbs == 0)
  1983. X    {
  1984. X        cnull (c);
  1985. X        return;
  1986. X    }
  1987. X    if (c == ' ')
  1988. X        nspace++;
  1989. X    else
  1990. X    {
  1991. X        while (nspace > 0)
  1992. X        {
  1993. X            null (' ');
  1994. X            nspace--;
  1995. X        }
  1996. X        cnull (c);
  1997. X    }
  1998. X    if (++cbc >= cbs)
  1999. X    {
  2000. X        null ('\n');
  2001. X        cbc = 0;
  2002. X        nspace = 0;
  2003. X    }
  2004. }
  2005. X
  2006. X
  2007. /*    fixibm - convert unix files to fixed record fromat records
  2008. **    for tape, translate to ebcdic
  2009. **    newlines are discarded
  2010. **    records are padded with spaces to the desired record length
  2011. */
  2012. X
  2013. fixibm (cc)
  2014. {
  2015. X    register c;
  2016. X
  2017. X    c = cc;
  2018. X    if (cflag&UCASE && c>='a' && c<='z')
  2019. X        c += 'A'-'a';
  2020. X    if (cflag&LCASE && c>='A' && c<='Z')
  2021. X        c += 'a'-'A';
  2022. X    c = atoe[c] & 0377;
  2023. X    if (cbs == 0)
  2024. X    {
  2025. X        null (c);
  2026. X        return;
  2027. X    }
  2028. X    /* translate tabs to blanks */
  2029. X    if (cc == '\t')
  2030. X    {
  2031. X        c = atoe[' '];
  2032. X        while ((cbc < cbs) && ( cbc+1 & 07 ))
  2033. X        {
  2034. X            null (c);
  2035. X            cbc ++;
  2036. X        }
  2037. X    }
  2038. X    else if (cc == '\n')
  2039. X    {
  2040. X        c = atoe[' '];
  2041. X        while (cbc < cbs)
  2042. X        {
  2043. X            null (c);
  2044. X            cbc++;
  2045. X        }
  2046. X        cbc = 0;
  2047. X        return;
  2048. X    }
  2049. X    if (cbc == cbs)
  2050. X        truncated++;
  2051. X    cbc++;
  2052. X    if (cbc <= cbs)
  2053. X        null (c);
  2054. }
  2055. X
  2056. X
  2057. /*    fix - convert unix files to fixed record format records for
  2058. **    tape, no character translation
  2059. **    newlines are discarded
  2060. **    records are padded with spaces up to the desired recordlength
  2061. */
  2062. X
  2063. fix (cc)
  2064. {
  2065. X    register c;
  2066. X
  2067. X    c = cc;
  2068. X    if (cbs == 0)
  2069. X    {
  2070. X        cnull (c);
  2071. X        return;
  2072. X    }
  2073. X    if (cc == '\n')
  2074. X    {
  2075. X        while (cbc < cbs)
  2076. X        {
  2077. X            null (' ');
  2078. X            cbc++;
  2079. X        }
  2080. X        cbc = 0;
  2081. X        return;
  2082. X    }
  2083. X    if (cbc == cbs)
  2084. X        truncated++;
  2085. X    cbc++;
  2086. X    if (cbc <= cbs)
  2087. X        cnull (c);
  2088. }
  2089. X
  2090. X
  2091. /*    convert unix disk file to ANSI variable blocked format D
  2092. **    files on tape.
  2093. **    newlines (\n) are discarded, i.e. taken as end-of-record indicators.
  2094. **    records do not span blocks
  2095. **    blocks not completely filled are padded with ANSI padding char '^'
  2096. **    to full output block size.
  2097. */
  2098. X
  2099. var (cc)
  2100. X    int cc;
  2101. {
  2102. X    register c, l;
  2103. X    register char *lrp;
  2104. X    int i;
  2105. X    c = cc;
  2106. X    if (cc == '\n')
  2107. X    {    /* end of input record reached */
  2108. X        l = (cbc > cbs ? cbs : cbc );
  2109. X
  2110. X        /* insert ANSI format record length field */
  2111. X        lrp = rbuf+4;
  2112. X        for ( i=4; i > 0; i-- )
  2113. X        {
  2114. X            *--lrp = (l % 10) + '0';
  2115. X            l = l / 10;
  2116. X        }
  2117. X
  2118. X    copyr:    /* copy record to output buffer */
  2119. X        lrp = rbuf;
  2120. X        l = (cbc > cbs ? cbs : cbc );
  2121. X        if ( obc + l <= obs)
  2122. X        {    /* record fits in block */
  2123. X            while (l--)
  2124. X                cnull (*lrp++);
  2125. X            cbc = 4;
  2126. X            rp = rbuf+4;
  2127. X            return;
  2128. X        }
  2129. X        else
  2130. X        {    /* pad the block, make new block */
  2131. X            l = obs - obc;
  2132. X            while (l--)
  2133. X                cnull ('^');
  2134. X            goto copyr;
  2135. X        }
  2136. X    }
  2137. X    if (cbc == cbs )    /* truncated record */
  2138. X        truncated ++;
  2139. X    cbc++;
  2140. X    if (cbc <= cbs )
  2141. X        *rp++ = c;        /* char to record */
  2142. }
  2143. X
  2144. X
  2145. /*    convert ANSI blocked variable format D records files on tape
  2146. **    to unix file on disk.
  2147. **    a newline (\n) will be append after every record on disk.
  2148. */
  2149. X
  2150. unvar (cc)
  2151. X    int cc;
  2152. {
  2153. X    register c;
  2154. X    c = cc;
  2155. X    if (cbc < 4)
  2156. X    {    /* still in length field */
  2157. X        if (c == '^')
  2158. X            return;
  2159. X        lr = lr * 10 + c - '0';
  2160. X        cbc ++;
  2161. X        if (cbc == 4 && lr == 4) 
  2162. X        {    /* empty record */
  2163. X            cbc = 0;
  2164. X            lr = 0;
  2165. X            null ('\n');
  2166. X        }
  2167. X        return;
  2168. X    }
  2169. X    cnull (c);
  2170. X    cbc ++;
  2171. X    if (cbc == lr)
  2172. X    {    /* at end of record */
  2173. X        cnull ('\n');
  2174. X        lr = 0;
  2175. X        cbc = 0;
  2176. X    }
  2177. }
  2178. X
  2179. X
  2180. /*    convert IBM blocked variable format V record files
  2181. **    to unix files on disk.
  2182. **    translate from ebcdic to ascii.
  2183. **    append newline (\n) to every record on disk.
  2184. */
  2185. X
  2186. unvaribm (cc)
  2187. {
  2188. X    register c;
  2189. X    c = cc;
  2190. X    if (cbc < 4)
  2191. X    {    /* still in record length field */
  2192. X        if (cbc == 0)
  2193. X            lr = c;
  2194. X        else if (cbc == 1)
  2195. X            lr = (lr << 8) + (c & 0377) ;
  2196. X        cbc ++;
  2197. X        if (cbc == 4 && lr == 4) 
  2198. X        {    /* empty record - shouldn't happen on ibm */
  2199. X            cbc = 0;
  2200. X            lr = 0;
  2201. X            null ('\n');
  2202. X        }
  2203. X        return;
  2204. X    }
  2205. X    cnull (etoa[c & 0377]);
  2206. X    cbc ++;
  2207. X    if (cbc == lr)
  2208. X    {    /* at end of record */
  2209. X        null ('\n');
  2210. X        lr = 0;
  2211. X        cbc = 0;
  2212. X    }
  2213. }
  2214. X
  2215. X
  2216. /*    convert unix files on disk to IBM blocked variable format V
  2217. **    record files on tape.
  2218. **    translate from ascii to ebcdic.
  2219. **    records do not span blocks.
  2220. **    blocks not completely filled are padded to output blocksize
  2221. **    with null characters (the block length field however contains
  2222. **    the block length without padding chars).
  2223. */
  2224. X
  2225. varibm (cc)
  2226. {
  2227. X    register c, l;
  2228. X    register char *lrp;
  2229. X
  2230. X    c = cc;
  2231. X    if (c == '\n')
  2232. X    {    /* end of input record */
  2233. X        l = (cbc > cbs ? cbs : cbc );
  2234. X        /* insert record length */
  2235. X        putlength (rbuf,l);
  2236. X
  2237. X    copyrec:    /* copy record to output buffer */
  2238. X        lrp = rbuf;
  2239. X        if (obc + l <= obs)
  2240. X        {    /* record fits in block */
  2241. X            if (obc + l == obs)
  2242. X            {    /* record first exactly */
  2243. X                /* insert block length */
  2244. X                putlength (obuf,obs);
  2245. X                while (l--)
  2246. X                    null (*lrp++);
  2247. X                obc = 4;
  2248. X                op  += 4;
  2249. X                cbc = 4;
  2250. X                rp  = rbuf+4;
  2251. X                return;
  2252. X            }
  2253. X            while (l--)
  2254. X                null (*lrp++);
  2255. X            cbc = 4;
  2256. X            rp = rbuf+4;
  2257. X            return;
  2258. X        }
  2259. X        else
  2260. X        {    /* complete block and write it */
  2261. X            /* insert block length */
  2262. X            putlength (obuf,obc);
  2263. X
  2264. X            /* pad with zero chars to obs */
  2265. X            l = obs - obc;
  2266. X            while (l-- )
  2267. X                null (0);
  2268. X            op = op + 4;
  2269. X            obc = 4;
  2270. X
  2271. X            /* block written, write record to next */
  2272. X            l = (cbc > cbs ? cbs : cbc );
  2273. X            goto copyrec;
  2274. X        }
  2275. X    }
  2276. X    if (cflag&UCASE && c>='a' && c<='z')
  2277. X        c += 'A'-'a';
  2278. X    else if (cflag&LCASE && c>='A' && c<='Z')
  2279. X        c += 'a'-'A';
  2280. X    c = atoe[c] & 0377;
  2281. X
  2282. X    if (cbc == cbs)
  2283. X        truncated++ ;        /* record truncated */
  2284. X    cbc++;
  2285. X    if (cbc <= cbs)
  2286. X        *rp++ = c;        /* char to record buffer */
  2287. }
  2288. X
  2289. X
  2290. /*    insert length to block or record.
  2291. **    IBM length field: byte 1 and 2 contain the length, byte 3 and 4 zero.
  2292. **    (don't forget: IBM count the bytes from left to right).
  2293. */
  2294. X
  2295. putlength (buf,len)
  2296. X    char *buf;
  2297. X    int len;
  2298. {
  2299. X    register char *p;
  2300. X
  2301. X    p = buf + 4;
  2302. X    *--p = 0; *--p = 0;        /* two zero bytes */
  2303. X    *--p = len & 0377;
  2304. X    *--p = len >> 8;        /* halfword with binary length */
  2305. }
  2306. X
  2307. X
  2308. /*    buffer translation routines
  2309. **    ebcdic to ascii and asci to ebcdic
  2310. */
  2311. X
  2312. toascii (buf,len)
  2313. X    char *buf;
  2314. X    int len;
  2315. {
  2316. X    register char *ip;
  2317. X    register c;
  2318. X    for (ip = buf; ip < buf+len; )
  2319. X    {
  2320. X        c = etoa[*ip &0377];
  2321. X        *ip++ = c;
  2322. X    }
  2323. }
  2324. X
  2325. toebcdic (buf,len)
  2326. X    char *buf;
  2327. X    int len;
  2328. {
  2329. X    register char *ip;
  2330. X    register c;
  2331. X    for (ip = buf; ip < buf+len; )
  2332. X    {
  2333. X        c = *ip;
  2334. X        *ip++ = atoe[c & 0377];
  2335. X    }
  2336. }
  2337. X
  2338. X
  2339. /*************************************************************************
  2340. ***    tape command emulation
  2341. *************************************************************************/
  2342. X
  2343. X
  2344. struct mtget mtg;
  2345. struct mtop mto;
  2346. X
  2347. X
  2348. tapeopen ()
  2349. {
  2350. X    if ((tapefid = open (tapename, 0)) < 0)
  2351. X        ioabort ("Cant open tape file\n");
  2352. X    mustbetape ();
  2353. X    taperew ();
  2354. }
  2355. X
  2356. X
  2357. tapecreat ()
  2358. {
  2359. X    if ((tapefid = creat (tapename, 0)) < 0)
  2360. X        ioabort ("Can't open tape file for writing / ring?\n");
  2361. X    mustbetape ();
  2362. X    taperew ();
  2363. }
  2364. X
  2365. mustbetape ()
  2366. {
  2367. X    if (ioctl (tapefid, MTIOCGET, &mtg) < 0) {
  2368. X        if (errno == ENOTTY) {
  2369. X            fprintf (stderr, "SLT: %s is not a tape device\n",
  2370. X                tapename);
  2371. X            exit (-1);
  2372. X        } else {
  2373. X            ioabort ("error getting tape status");
  2374. X        }
  2375. X    }
  2376. }
  2377. X
  2378. tapewtm ()
  2379. {
  2380. X    if (debug)
  2381. X        printf ("\n---------------- TAPEMARK\n");
  2382. X    mto.mt_op = MTWEOF;
  2383. X    mto.mt_count = 1;
  2384. X    if (ioctl (tapefid, MTIOCTOP, &mto) < 0)
  2385. X        perror ("tape/wtm");
  2386. }
  2387. X
  2388. X
  2389. tapefsf ()
  2390. {
  2391. X    mto.mt_op = MTFSF;
  2392. X    mto.mt_count = 1;
  2393. X    if (ioctl (tapefid, MTIOCTOP, &mto) < 0)
  2394. X        perror ("tape/fsf");
  2395. }
  2396. X
  2397. X
  2398. taperew ()
  2399. {
  2400. X    mto.mt_op = MTREW;
  2401. X    mto.mt_count = 1;
  2402. X    ioctl (tapefid, MTIOCTOP, &mto);
  2403. X    /* ignore errors on rewind, as taperew may be called in closed
  2404. X    ** file state, after some error had occurred, just to be safe  */
  2405. }
  2406. X
  2407. X
  2408. /*************************************************************************
  2409. ***    writing messages, error reports
  2410. *************************************************************************/
  2411. X
  2412. ioabort (msgtext)
  2413. X    char *msgtext;
  2414. {
  2415. X    perror (msgtext);
  2416. X    taperew ();
  2417. X    exit (-1);
  2418. }
  2419. X
  2420. X
  2421. stopit (msgtext)
  2422. X    char *msgtext;
  2423. {
  2424. X    fprintf( stderr, "\nABORT: %s\n", msgtext);
  2425. X    if (debug)
  2426. X        abort ();    /* trap for debugger if any,
  2427. X                ** write 'core' file */
  2428. X    else
  2429. X        taperew ();
  2430. X        exit (-1);
  2431. }
  2432. X
  2433. X
  2434. err (msgtext)
  2435. X    char *msgtext;
  2436. {
  2437. X    fprintf (stderr, "\nERROR: %s\n", msgtext);
  2438. }
  2439. X
  2440. X
  2441. cmpstr (s1,s2)
  2442. X    char *s1, *s2;
  2443. {
  2444. X    register char *p1, *p2;
  2445. X    char    c1, c2;
  2446. X
  2447. X    p1 = s1;
  2448. X    p2 = s2;
  2449. X    while ( (c1 = *p1++) == ( c2 = *p2++))
  2450. X        if (c1 == '\0')
  2451. X            return(0);
  2452. X    return (c2 - c1);
  2453. }
  2454. X
  2455. X
  2456. upcase (s)
  2457. X    char *s;
  2458. {
  2459. X    register char *p;
  2460. X    register char c;
  2461. X    p = s;
  2462. X    while (c = *p)
  2463. X        if ('a' <= c && c <= 'z')
  2464. X            *p++ = c + 'A'-'a';
  2465. X        else
  2466. X            p++;
  2467. }
  2468. X
  2469. X
  2470. /*************************************************************************
  2471. ***    end of program 'slt'
  2472. *************************************************************************/
  2473. SHAR_EOF
  2474. chmod 0640 slt-20.c ||
  2475. echo 'restore of slt-20.c failed'
  2476. Wc_c="`wc -c < 'slt-20.c'`"
  2477. test 43183 -eq "$Wc_c" ||
  2478.     echo 'slt-20.c: original size 43183, current size' "$Wc_c"
  2479. fi
  2480. exit 0
  2481. 
  2482.  
  2483.